﻿using System;
using System.Collections.Generic;
using System.Linq;
using Missbot.Common;
using Missbot.Core;
using Missbot.Core.Base;
using Missbot.Core.Cache;
using Missbot.Core.Common;
using Dolany.UtilityTool;
using Missbot.AIModule.Base;
using Missbot.AIModule.OnlineStore;
using Missbot.AIModule.Pet.Cooking;
using Missbot.AIModule.Pet.Expedition;
using Missbot.AIModule.Vip;
using Missbot.Model.MsgCmds.Drive;

namespace Missbot.AIModule.Pet
{
    /// <summary>
    /// 宠物基础模块
    /// </summary>
    public class PetMod : IAIModule
    {
        public override string Name => "宠物";
        public override string ParentTag => "宠物功能";

        #region Svcs

        public PicReviewSvc PicReviewSvc { get; set; }
        public PetLevelSvc PetLevelSvc { get; set; }
        public WaiterSvc WaiterSvc { get; set; }
        public ChannelMgr ChannelMgr { get; set; }
        public HonorSvc HonorSvc { get; set; }
        public CookingDietSvc CookingDietSvc { get; set; }

        #endregion

        private static PetConfig PetConfig => Configger<AIConfigBase>.AIConfig.Pet;

        /// <summary>
        /// 喂食宠物时间间隔（小时）
        /// </summary>
        private const int FeedInterval = 2;

        public override void Initialization()
        {
            base.Initialization();
            PicReviewSvc.Register("宠物头像", SetPetPicCallBack);
        }

        private static void SetPetPicCallBack(PicReviewRecord record)
        {
            if (record.Status == PicReviewStatus.Refused)
            {
                return;
            }

            var pet = PetRecordDA.Get(record.UserID);

            if (pet.FileID != PetConfig.DefaultPetAvatar)
            {
                MsgSender.PushMsg(new FileDeleteCmd { FileID = pet.FileID });
            }

            pet.FileID = record.FileID;
            pet.Update();
        }

        [ModuleEnter(Command = "我的宠物", Description = "查看自己的宠物的状态")]
        public bool MyPet(InboxSession session)
        {
            var pet = PetRecordDA.Get(session.User.ID);

            var levelModel = PetLevelSvc[pet.Level];

            var HasExtEndur = VipArmerDA.Get(session.User.ID)?.CheckArmer("耐力护符") ?? false;
            var extEndur = HasExtEndur ? "(+10)" : string.Empty;
            var petEndur = levelModel.Endurance - PetEnduranceDA.Get(session.User.ID).ConsumeTotal + (HasExtEndur ? 10 : 0);

            var buffer = new OutputBuffer(session);
            buffer.AddFile(pet.FileID);
            buffer.AddPair(new Dictionary<string, string>
            {
                ["名称"] = pet.Name,
                ["种族"] = pet.PetNo,
                ["食性"] = pet.Attribute ?? "无",
                ["等级"] = LevelHelper.LevelEmoji(pet.Level),
                ["❤"] = levelModel.HP.ToString(),
                ["耐力"] = $"{petEndur}/{levelModel.Endurance}{extEndur}",
                ["经验值"] = $"{pet.Exp}/{levelModel.Exp}"
            });

            if (!pet.Skills.IsNullOrEmpty())
            {
                buffer.Add($"技能：{pet.Skills.Select(p => $"{p.Key}({p.Value})").JoinToString(",")}");
            }

            if (pet.RemainSkillPoints > 0)
            {
                buffer.Add($"可用技能点：{pet.RemainSkillPoints}");
            }

            buffer.Send();
            return true;
        }

        [ModuleEnter(Command = "重命名宠物 设定宠物名称", Description = "重命名自己的宠物（名字不能超过十个字）", DailyLimit = 4, SyntaxHint = "[宠物名称]")]
        public bool RenamePet(InboxSession session, string name)
        {
            if (name.Length > 10)
            {
                session.SendBack("名字不能超过10个字！");
                return false;
            }

            var pet = PetRecordDA.Get(session.User.ID);
            pet.Name = name;
            pet.Update();

            session.SendBack("重命名成功！");
            return true;
        }

        [ModuleEnter(Command = "设定宠物种族 设置宠物种族", Description = "设定宠物的种族（不能超过十个字）", DailyLimit = 4, SyntaxHint = "[种族名称]")]
        public bool SetPetKind(InboxSession session, string name)
        {
            if (name.Length > 10)
            {
                session.SendBack("种族不能超过10个字！");
                return false;
            }

            var pet = PetRecordDA.Get(session.User.ID);
            pet.PetNo = name;
            pet.Update();

            session.SendBack("设定成功！");
            return true;
        }

        [ModuleEnter(Command = "设定宠物头像 设置宠物头像", Description = "上传宠物头像的图片（不能超过300KB）", DailyLimit = 4)]
        public bool SetPetPic(InboxSession session)
        {
            if (session.Files.IsNullOrEmpty())
            {
                session.SendBack("未读取到图片！");
                return false;
            }

            var osPerson = OSPersonDA.GetPerson(session.User.ID);
            if (osPerson.Golds < 300)
            {
                session.SendBack($"你的金币余额不足（{osPerson.Golds.CurencyFormat()}/{300.CurencyFormat()}）");
                return false;
            }

            if (!WaiterSvc.WaitForConfirm_Gold(session, 300))
            {
                session.SendBack("操作取消！");
                return false;
            }

            var marker = Guid.NewGuid().ToString("N");
            MsgSender.PushMsg(new UploadUrlCmd
            {
                FolderID = PetConfig.PetAvatarStoreFolderID,
                URL = session.Files.First().Url,
                Marker = marker
            });
            var uploadFinish = ChannelMgr.Wait("UrlUploadFinished", info => info.Addition.GetString("Marker") == marker);
            if (uploadFinish == null)
            {
                session.SendBack("上传失败！请稍后再试！");
                return false;
            }

            var file = uploadFinish.Files.First();
            MsgSender.PushMsg(new RenameFileCmd { FileID = file.ID, Name = $"PetAvatar_{session.User.ID}" });
            session.SendBack("上传成功！待审核通过后方可生效！");
            var review = new PicReviewRecord
            {
                GroupID = session.Group.ID,
                GroupName = session.Group.Name,
                UserID = session.User.ID,
                UserName = session.User.Name,
                Usage = "宠物头像",
                FileID = file.ID
            };
            PicReviewSvc.AddReview(review);

            osPerson.Golds -= 300;
            osPerson.Update();

            return true;
        }

        [ModuleEnter(Command = "设定宠物食性 设置宠物食性", Description = "设定宠物的初始食性", DailyLimit = 1)]
        public bool SetPetAttr(InboxSession session)
        {
            var pet = PetRecordDA.Get(session.User.ID);
            var needGolds = false;
            OSPerson osPerson = null;
            if (!string.IsNullOrEmpty(pet.Attribute))
            {
                osPerson = OSPersonDA.GetPerson(session.User.ID);

                if (osPerson.Golds < 300)
                {
                    session.SendBack($"金币余额不足！({osPerson.Golds.CurencyFormat()}/{300.CurencyFormat()})");
                    return false;
                }

                if (!WaiterSvc.WaitForConfirm_Gold(session, 300))
                {
                    session.SendBack("操作取消");
                    return false;
                }

                needGolds = true;
            }

            var randAttrs = Rander.RandSort(PetExtent.AllAttributes.ToArray());
            var msg = $"请选择宠物食性：\n{string.Join("\n", randAttrs.Select((p, idx) => $"{idx + 1}:{p}"))}";
            var selectedIdx = WaiterSvc.WaitForNum(session, msg, i => i > 0 && i <= randAttrs.Length);
            if (selectedIdx == -1)
            {
                session.SendBack("操作取消");
                return false;
            }

            pet.Attribute = randAttrs[selectedIdx - 1];
            pet.Update();

            if (needGolds)
            {
                osPerson.Golds -= 300;
                osPerson.Update();
            }

            session.SendBack("设定成功！");
            return true;
        }

        [ModuleEnter(Command = "喂食宠物", Description = "喂给宠物指定的物品或菜肴（请遵循宠物的食性）", SyntaxHint = "[物品名/菜肴名]")]
        public bool FeedPet(InboxSession session, string name)
        {
            var pet = PetRecordDA.Get(session.User.ID);
            var expRec = ExpeditionRecordDA.GetLastest(session.User.ID);
            if (expRec != null && expRec.IsExpediting())
            {
                session.SendBack($"{pet.Name}正在【{expRec.Scene}】进行一项伟大的远征，请于{expRec.EndTime:yyyy-MM-dd HH:mm:ss}后再试！");
                return false;
            }

            if (string.IsNullOrEmpty(pet.Attribute))
            {
                session.SendBack("请先设置宠物食性！");
                return false;
            }

            if (pet.LastFeedTime != null && pet.LastFeedTime.Value.AddHours(FeedInterval) > DateTime.Now)
            {
                var msg = $"{pet.Name}还饱着呢，不想吃东西（请与{pet.LastFeedTime.Value.AddHours(FeedInterval)}后再试）";
                session.SendBack(msg);
                return false;
            }

            var item = HonorSvc.FindItem(name);
            if (item != null)
            {
                return FeedPetWithItem(session, pet, item);
            }

            var diet = CookingDietSvc[name];
            if (diet != null)
            {
                return FeedPetWithDiet(session, pet, diet);
            }

            session.SendBack("未查找到相关物品或菜肴！");
            return false;
        }

        /// <summary>
        /// 用物品喂食宠物
        /// </summary>
        /// <param name="session"></param>
        /// <param name="pet"></param>
        /// <param name="item"></param>
        /// <returns></returns>
        private static bool FeedPetWithItem(InboxSession session, PetRecord pet, DriftBottleItemModel item)
        {
            if (item.Attributes == null)
            {
                session.SendBack("该物品无法投喂！");
                return false;
            }

            if (!item.Attributes.Contains(pet.Attribute))
            {
                session.SendBack($"{pet.Name}说不想吃这个东西（请喂食正确特性的物品）");
                return false;
            }

            var honorRecord = ItemCollectionDA.Get(session.User.ID);
            if (!honorRecord.CheckItem(item.Name))
            {
                session.SendBack("你没有该物品！");

                return false;
            }

            var resMsg = $"{pet.Name}兴奋的吃掉了 {item.Name}，并打了个饱嗝\n";

            pet.LastFeedTime = DateTime.Now;
            resMsg += pet.ExtGain(item.Exp);
            honorRecord.ItemConsume(item.Name);
            honorRecord.Update();

            session.SendBack(resMsg);
            return true;
        }

        /// <summary>
        /// 用菜肴喂食宠物
        /// </summary>
        /// <param name="session"></param>
        /// <param name="pet"></param>
        /// <param name="diet"></param>
        /// <returns></returns>
        private static bool FeedPetWithDiet(InboxSession session, PetRecord pet, CookingDiet diet)
        {
            if (!diet.Attributes.Contains(pet.Attribute))
            {
                session.SendBack($"{pet.Name}说不想吃这个东西（请喂食正确特性的菜肴）");
                return false;
            }

            var cookingRec = CookingRecordDA.Get(session.User.ID);
            if (!cookingRec.CheckDiet(diet.Name))
            {
                session.SendBack("你没有该菜肴！");
                return false;
            }

            var resMsg = $"{pet.Name}兴奋的吃掉了 {diet.Name}，并打了个饱嗝\n";

            pet.LastFeedTime = DateTime.Now;
            resMsg += pet.ExtGain(diet.Exp);
            cookingRec.DietConsume(diet.Name);
            cookingRec.Update();

            session.SendBack(resMsg);
            return true;
        }

        [ModuleEnter(Command = "宠物等级分布", Description = "查看宠物的等级分布", AuthLvl = AuthorityLevel.Developer)]
        public bool PetLevelAnalyze(InboxSession session)
        {
            var data = PetRecordDA.LevelAnalyze();
            var msg = string.Join("\n", data.Select(p => $"{p.Key}:{p.Value}"));

            session.SendBack(msg);
            return true;
        }

        [ModuleEnter(Command = "宠物等级排行", Description = "宠物等级排行")]
        public bool PetLevelRank(InboxSession session)
        {
            var data = PetRecordDA.LevelTop(10);
            var msgList = data.Select((p, idx) => $"{idx + 1}:{p.Name}({LevelHelper.LevelEmoji(p.Level)})({p.Exp}/{PetLevelSvc[p.Level].Exp})");
            var msg = string.Join("\n", msgList);

            session.SendBack(msg);
            return true;
        }
    }
}